package cn.org.wangchangjiu.sqltomongo.core.parser.data;

import cn.org.wangchangjiu.sqltomongo.core.analyzer.select_option.ExpressionAnalyzer;
import cn.org.wangchangjiu.sqltomongo.core.common.AggregationFunction;
import lombok.Builder;
import lombok.Data;

import java.io.Serializable;
import java.util.Map;
import java.util.Objects;

@Data
@Builder
public class MatchData implements Serializable {

    /**
     *  解析优先级
     */
    private int priority;

    // 排序 用户后面 Java 8 对List 先按优先级排序 再按 sort 排序，
    // 但是测试之后 貌似 两次排序不能同时 降序，必须一个降序一个升序，所以加了一个字段 恶心一把
    private int sort;

    /**
     *  是否是操作符
     */
    private Boolean isOperator;

    /**
     *  表达式
     */
    private ExpressionItem expression;

    /**
     *  having的分组集合名
     */
    private String havingGroupCollectionName;

    private boolean isHavingMatch;

    public MatchData(){}

    public MatchData(int priority, int sort, boolean isOperator, ExpressionItem expression,String havingGroupCollectionName,boolean isHavingMatch){
        this.priority = priority;
        this.sort = sort;
        this.isOperator = isOperator;
        this.expression = expression;
        this.havingGroupCollectionName = havingGroupCollectionName;
        this.isHavingMatch = isHavingMatch;
    }

    public void setHavingGroupCollectionName(String havingGroupCollectionName) {
        this.havingGroupCollectionName = havingGroupCollectionName;
    }

    /**
     * 改筛选条件是否为having筛选条件
     * @return boolean
     */
    public boolean isGroupByFieldHavingMatch() {
        return havingGroupCollectionName!=null && !havingGroupCollectionName.isEmpty();
    }

    public String getField(TableNameManager tableNameManager) {
        //普通的a.id=1(a为主表) 或 id=1 形式，应当返回：id
        String r = "";
        MatchData.RelationExpressionItem expression = (MatchData.RelationExpressionItem) getExpression();
        r = expression.getField();

        //有连表的，且表名不是主表，如b.id=1返回:b.id
        Map<String, LookUpData> joinTables = tableNameManager.getJoinTables();
        String exprTable = expression.getTableAlias();
        String majorTable = tableNameManager.getMajorTableAlias();
        if (joinTables != null && exprTable!=null && majorTable!=null && !Objects.equals(majorTable, exprTable)) {
            r = joinTables.get(exprTable).getAs().concat(".").concat(r);
        }

        //having
        if(isHavingMatch()){
            if(expression.hasFunc()){
                //带有聚合函数，说明需要提取到group中进行计算的，需要起别名（having中优先）
                r = expression.getGroupAlias();
            }else if(isGroupByFieldHavingMatch()){
                //使用having的分组依据字段的，要加上分组依据前缀（having中次优先）
                r = buildHavingMatchField(expression);
            }
        }
        return r;
    }

    private String buildHavingMatchField(RelationExpressionItem expression) {
        return getHavingGroupCollectionName() + "." + expression.getField();
    }

    /**
     * 获取筛选表达式的等号前的原始字段（不包含Group分组依据集合前缀）
     * @return string
     */
    public String getOriginExpressionField() {
        if (isOperator) {
            //操作符直接返回null
            return null;
        }
        return ((MatchData.RelationExpressionItem) getExpression()).getField();
    }

    public boolean isHavingMatch() {
        return isHavingMatch;
    }


    interface ExpressionItem {}

    @Data
    public static class OperatorExpressionItem implements ExpressionItem {

        private String operatorName;
        public OperatorExpressionItem(){}
        public OperatorExpressionItem(String operatorName){
            this.operatorName = operatorName;
        }

    }

    // 关系表达式 列入 b.style = ?
    @Data
    public static class RelationExpressionItem implements ExpressionItem {
        /**
         *  表别名
         */
        private String tableAlias;
        /**
         *  字段
         */
        private String field;
        /**
         *  group计算式的别名
         */
        private String groupAlias;
        /**
         *  关系操作符 =、 >、 <
         */
        private String operator;
        /**
         *  值
         */
        private Object value;
        /**
         *  聚合函数
         */
        private AggregationFunction function;

        public RelationExpressionItem(){}

        public RelationExpressionItem(String tableAlias, String field, String operator, AggregationFunction function, Object value){
            this.tableAlias = tableAlias;
            this.field = field;
            this.groupAlias = ExpressionAnalyzer.FUNC_PRE_STR+(function!=null?(function.name()+"_"):"")+(tableAlias!=null?(tableAlias+"_"):"")+field;
            this.operator = operator;
            this.function = function;
            this.value = value;
        }

        public String getGroupAlias(){
            return groupAlias;
        }

        public boolean hasFunc() {
            return function!=null;
        }
    }
}
